import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import {
    exec,
    spawnSync,
    SpawnSyncOptionsWithStringEncoding
} from 'node:child_process';
import { isType } from '../m.common';
import { findString } from '../m.string';

/**
 * 使用子进程执行一条命令
 * @param { string } command 执行的命令
 * @param { Partial<SpawnSyncOptionsWithStringEncoding> } options 执行命令的参数
 * **/
export const execCommand = (
    command: string,
    options: Partial<SpawnSyncOptionsWithStringEncoding> = {}
): Promise<string> => {
    return new Promise((resolve, reject) => {
        const commandList = command.split(' '),
            spawnOption = Object.assign(
                {
                    shell: true,
                    encoding: 'utf8',
                    cwd: process.cwd()
                },
                options
            );
        if (!fs.existsSync(spawnOption.cwd || ''))
            return reject('exec command cwd is not exists...');

        const result = spawnSync(
            commandList[0],
            commandList.slice(1),
            spawnOption
        );
        const stdout = result.stdout?.trim?.();
        const error = result.error || result.stderr;
        if (error && findString(error as string, ['error', 'Error', 'fatal:']))
            return reject(error);
        else return resolve(stdout);
    });
};

/**
 * 获取系统信息
 * @returns { string } platform 系统平台
 * @returns { string } digit 系统位数
 * @returns { boolean } isWindow 是否是windows系统
 * @returns { boolean } isMac 是否时mac系统
 * @returns { boolean } isWin64 是否是win64
 * @returns { boolean } isWin32 是否是win32
 * **/
export const getSystemInfo = () => {
    const platform = process.platform;
    const systemDigit = process.arch;
    return {
        platform,
        digit: systemDigit,
        isWindow: platform === 'win32',
        isMac: platform === 'darwin',
        isWin64: systemDigit === 'x64',
        isWin32: systemDigit !== 'x64'
    };
};

/**
 * 获取当前系统用户的家目录
 * **/
export const getHome = (): string => {
    return os.homedir();
};

/**
 * 获取系统的 appData目录
 * **/
export const getAppData = () => {
    const homedir = getHome();
    return getSystemInfo().isWindow
        ? path.resolve(homedir, 'AppData/Roaming')
        : getSystemInfo().isMac
          ? path.join(homedir, '/')
          : path.resolve(__dirname);
};

/**
 * 根据appData目录为基准，获取路径
 * @param { string } refer 参照路径
 * **/
export const getReferToAppData = (refer: string): string => {
    return path.resolve(getAppData(), refer || '');
};

/**
 * 根据进程的名称，模糊查询，获取进程的PID
 * @param { string } name 进程的名称
 * **/
export const getPidByName = (name: string): Promise<Array<number>> => {
    const isWindows = getSystemInfo().isWindow;
    const command = isWindows ? 'tasklist' : 'ps -ef';
    const pidList: Array<number> = [];
    return new Promise((resolve) => {
        execCommand(command)
            .then((result) => {
                const lines = result.split(isWindows ? '\r\n' : '\n');
                for (let i = 0; i < lines.length; i++) {
                    if (lines[i].includes(name)) {
                        const columns = lines[i].split(/\s+/);
                        const pid = isWindows ? columns[1] : columns[2];
                        pidList.push(parseInt(pid));
                    }
                }
                resolve(pidList.filter((item) => item));
            })
            .catch(() => {
                resolve([]);
            });
    });
};

/**
 * 提供进程的名称，模糊查询进程是否存在
 * @param  { string } processName 进程名称
 * **/
export const isActiveProcessByName = async (
    processName: string
): Promise<boolean> => {
    const processList = await getPidByName(processName);
    return !!processList.length;
};

/**
 * 提供一个PID，查看这个PID是否正在运行
 * @param {string} pid 进程ID
 * **/
export const isActiveProcessByPid = async (pid: string) => {
    const isWindow = getSystemInfo().isWindow;
    const command = isWindow ? `tasklist /FI "PID eq ${pid}"` : 'ps -p ${pid}';
    return new Promise((resolve) => {
        execCommand(command)
            .then((res) => {
                resolve(res.includes(pid));
            })
            .catch(() => {
                resolve(false);
            });
    });
};

/**
 * 根据进程的PID，结束此进程
 * @param { number | Array<number> } pid 进程PID
 * **/
export const killProcessPid = (
    pid: number | Array<number>
): Promise<unknown> => {
    if (!pid) return Promise.resolve(false);
    if (!isType(pid, 'array')) pid = [pid as number];

    const tasks: Array<Promise<unknown>> = [],
        isWindows = getSystemInfo().isWindow;
    function killTak(id: number) {
        const killCommand = isWindows
            ? `taskkill /F /PID ${id}`
            : `kill -9 ${id}`;
        return new Promise((resolve) => {
            exec(killCommand, (err) => {
                if (err) {
                    resolve(false);
                    return;
                }
                resolve(true);
            });
        });
    }
    (pid as Array<number>).forEach((id) => tasks.push(killTak(id)));
    return Promise.all(tasks);
};

/**
 * 提供进程的名称，结束掉此进程，名称会模糊查询
 * @param { string } processName 进程的名称
 * **/
export const killProcessName = (processName: string): Promise<unknown> => {
    return getPidByName(processName).then((list) => {
        list.forEach((pid) => {
            killProcessPid(pid);
        });
        return list;
    });
};
